import { ipcRenderer, contextBridge } from 'electron'

// --------- Expose some API to the Renderer process ---------
contextBridge.exposeInMainWorld('ipcRenderer', {
  on(...args: Parameters<typeof ipcRenderer.on>) {
    const [channel, listener] = args
    return ipcRenderer.on(channel, (event, ...args) => listener(event, ...args))
  },
  off(...args: Parameters<typeof ipcRenderer.off>) {
    const [channel, ...omit] = args
    return ipcRenderer.off(channel, ...omit)
  },
  send(...args: Parameters<typeof ipcRenderer.send>) {
    const [channel, ...omit] = args
    return ipcRenderer.send(channel, ...omit)
  },
  invoke(...args: Parameters<typeof ipcRenderer.invoke>) {
    const [channel, ...omit] = args
    return ipcRenderer.invoke(channel, ...omit)
  },

  // You can expose other APTs you need here.
  // ...
})

// 暴露MQTT服务接口
contextBridge.exposeInMainWorld('mqtt', {
  connect: (config: any) => ipcRenderer.invoke('mqtt:connect', config),
  disconnect: () => ipcRenderer.invoke('mqtt:disconnect'),
  publish: (topic: string, message: any, options: any = {}) =>
    ipcRenderer.invoke('mqtt:publish', { topic, message, options }),
  subscribe: (topics: string | string[]) =>
    ipcRenderer.invoke('mqtt:subscribe', { topics }),
})

// 暴露自动化服务控制接口
contextBridge.exposeInMainWorld('automation', {
  start: (data: any[]) => ipcRenderer.invoke('start-automation', data),
  stop: (): Promise<{ success: boolean, isRunning: boolean }> => ipcRenderer.invoke('stop-automation')
})

// 暴露错误处理API给渲染进程
contextBridge.exposeInMainWorld('errorHandler', {
  // 上报新错误
  reportError: (error: { type: string, message: string, stack?: string, info?: any, source?: string }) =>
    ipcRenderer.invoke('report-error', error),

  // 获取所有错误
  getAllErrors: () => ipcRenderer.invoke('error:getAll'),

  // 清除所有错误
  clearErrors: () => ipcRenderer.invoke('error:clear'),

  // 订阅新错误通知
  onNewError: (callback: (error: any) => void) => {
    const listener = (_event: any, error: any) => callback(error)
    ipcRenderer.on('error:new', listener)
    return () => ipcRenderer.removeListener('error:new', listener)
  }
})

// 暴露环境变量给渲染进程
contextBridge.exposeInMainWorld('__VITE_TENANT_ENABLE__', process.env.VITE_TENANT_ENABLE || 'false')

// --------- Preload scripts loading ---------
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
  return new Promise((resolve) => {
    if (condition.includes(document.readyState)) {
      resolve(true)
    } else {
      document.addEventListener('readystatechange', () => {
        if (condition.includes(document.readyState)) {
          resolve(true)
        }
      })
    }
  })
}

const safeDOM = {
  append(parent: HTMLElement, child: HTMLElement) {
    if (!Array.from(parent.children).find(e => e === child)) {
      return parent.appendChild(child)
    }
  },
  remove(parent: HTMLElement, child: HTMLElement) {
    if (Array.from(parent.children).find(e => e === child)) {
      return parent.removeChild(child)
    }
  },
}

/**
 * https://tobiasahlin.com/spinkit
 * https://connoratherton.com/loaders
 * https://projects.lukehaas.me/css-loaders
 * https://matejkustec.github.io/SpinThatShit
 */
function useLoading() {
  const className = `loaders-css__square-spin`
  const styleContent = `
@keyframes square-spin {
  25% { transform: perspective(100px) rotateX(180deg) rotateY(0); }
  50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
  75% { transform: perspective(100px) rotateX(0) rotateY(180deg); }
  100% { transform: perspective(100px) rotateX(0) rotateY(0); }
}
.${className} > div {
  animation-fill-mode: both;
  width: 50px;
  height: 50px;
  background: #fff;
  animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
}
.app-loading-wrap {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #282c34;
  z-index: 9;
}
    `
  const oStyle = document.createElement('style')
  const oDiv = document.createElement('div')

  oStyle.id = 'app-loading-style'
  oStyle.innerHTML = styleContent
  oDiv.className = 'app-loading-wrap'
  oDiv.innerHTML = `<div class="${className}"><div></div></div>`

  return {
    appendLoading() {
      safeDOM.append(document.head, oStyle)
      safeDOM.append(document.body, oDiv)
    },
    removeLoading() {
      safeDOM.remove(document.head, oStyle)
      safeDOM.remove(document.body, oDiv)
    },
  }
}

// ----------------------------------------------------------------------

const { appendLoading, removeLoading } = useLoading()
domReady().then(appendLoading)

window.onmessage = (ev) => {
  ev.data.payload === 'removeLoading' && removeLoading()
}

setTimeout(removeLoading, 4999)

// Add global error handler to catch errors in the preload script
window.addEventListener('error', (event) => {
  const error = {
    type: 'preloadError',
    message: event.message || 'Unknown error in preload script',
    stack: event.error?.stack,
    source: 'preload'
  }

  ipcRenderer.invoke('report-error', error)
})

window.addEventListener('unhandledrejection', (event) => {
  const error = {
    type: 'preloadUnhandledRejection',
    message: event.reason?.message || String(event.reason) || 'Unhandled rejection in preload script',
    stack: event.reason?.stack,
    source: 'preload'
  }

  ipcRenderer.invoke('report-error', error)
})
